// 第 4 步：实现 addToEpollList

// step 1:
// 在 tcp_server.h 中写好基本的 #pragma once，并包含 tcp_socket.h（间接依赖
// socket_utils、logging 等模块）。暂时只保留命名空间和空结构体声明
#pragma once

#include <functional>
#include <string>
#include <sys/epoll.h>
#include <vector>

#include "tcp_socket.h"
#include "logging.h"
#include "time_utils.h"

namespace Common {
// step 2:
// 服务器需要一个监听用的 TCPSocket、用于 epoll 的 fd、事件数组、收发队列、回调等。构造函数接收 Logger&，并让监听 socket 复用同一个 logger
struct TCPServer {
  explicit TCPServer(Logger &logger)
      : listener_socket_(logger), logger_(logger) {}

  // step 3:
  // 在头文件中补充三个公开方法：listen、poll、sendAndRecv，以及一个私有辅助方法 addToEpollList。每个函数简短注释说明职责
  auto listen(const std::string &iface, int port) -> void;
  auto poll() noexcept -> void;
  auto sendAndRecv() noexcept -> void;

private:
  auto addToEpollList(TCPSocket *socket);

public:
  int epoll_fd_ = -1;
  TCPSocket listener_socket_;
  epoll_event events_[1024];

  std::vector<TCPSocket *> receive_sockets_;
  std::vector<TCPSocket *> send_sockets_;

  std::function<void(TCPSocket *s, Nanos rx_time)> recv_callback_ = nullptr;
  std::function<void()> recv_finished_callback_ = nullptr;

  std::string time_str_;
  Logger &logger_;
};

// step 4:
// 切换到 tcp_server.cpp。首先包含头文件，并在 Common 命名空间内实现 addToEpollList：构造边缘触发、读事件的 epoll_event，把 TCPSocket* 放进 event.data.ptr，方便回调时取回
auto TCPServer::addToEpollList(TCPSocket *socket) {
  epoll_event ev{EPOLLET | EPOLLIN, {reinterpret_cast<void *>(socket)}};
  return !epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, socket->socket_fd_, &ev);
}
}  // namespace Common